<template>
    <div>
        <el-button type="primary" @click="toggleVisible">显示隐藏</el-button>

        <div
            v-Drag="{ dragTotal: false, width: '50%', height: '50%' }"
            :data-isStop="isStop"
            v-if="dragVisible"
        >
            <div class="header"></div>
            <div class="content">
                <el-button type="primary" @click="toggleStopDrag"
                    >拖动停止</el-button
                >
                <el-input
                    v-model="test"
                    placeholder="请输入内容"
                    @keypress="handleKeyPress"
                ></el-input>
            </div>
        </div>
    </div>
</template>

<script lang="ts" setup>
import { ref, Directive, DirectiveBinding } from "vue";

const test = ref("");
const dragVisible = ref(false);
const toggleVisible = () => {
    dragVisible.value = !dragVisible.value;
};
const handleKeyPress = (e: KeyboardEvent) => {
    if (e.code == "Space") {
        e.preventDefault();
    }
};

const isStop = ref(false);
const toggleStopDrag = () => {
    isStop.value = !isStop.value;
    console.log(isStop.value, "------");
};
const vDrag: Directive = {
    created() {},
    beforeMount() {},
    mounted(el: HTMLElement, dir: DirectiveBinding, vNode, preVNode) {
        const oldElement = document.getElementById("uniqueDragBoxId");
        if (oldElement) {
            // 防止重复添加
            oldElement.parentElement?.remove();
        }
        const box = document.createElement("div");
        const wrapper = document.createElement("div");
        const clientWidth =
            window.innerWidth ||
            document.documentElement.clientWidth ||
            document.body.clientWidth;
        const clientHeight =
            window.innerHeight ||
            document.documentElement.clientHeight ||
            document.body.clientHeight;
        const { dragTotal, width, height } = dir.value;
        let leftValue = "";
        let topValue = "";
        // 判断传来的宽高是px还是百分比 让使用v-drag的元素宽高自定义
        if (width.endsWith("%")) {
            const w = parseInt(width.replace("%", ""));
            el.style.width = `${clientWidth * (w / 100)}px`;
            leftValue = ((100 - w) * clientWidth) / 100 / 2 + "px";
        } else {
            el.style.width = width;
            leftValue = (clientWidth - width.replace("px", "")) / 2 + "px";
        }
        if (height.endsWith("%")) {
            const h = parseInt(height.replace("%", ""));
            el.style.height = `${clientHeight * (h / 100)}px`;
            topValue = ((100 - h) * clientHeight) / 100 / 2 + "px";
        } else {
            el.style.height = height;
            topValue = (clientHeight - height.replace("px", "")) / 2 + "px";
        }
        box.id = "uniqueDragBoxId";
        box.style.position = "absolute";
        box.style.pointerEvents = "all";
        // 使元素向左和向上各自偏屏幕宽度减去自身宽度的一半进行居中
        box.style.left = leftValue;
        box.style.top = topValue;
        // 最外层盒子隐藏滚动
        wrapper.style.width = "100%";
        wrapper.style.height = "100%";
        wrapper.style.zIndex = "9999999 !important";
        wrapper.style.pointerEvents = "none";
        wrapper.style.overflow = "hidden";
        box.appendChild(el);
        wrapper.appendChild(box);
        document.body.appendChild(wrapper);
        document.body.style.overflow = "hidden";
        const oDiv = (dragTotal ? el : el.firstChild) as HTMLElement;
        // const oDiv = el; // 当前元素
        // const minTop = oDiv.getAttribute("drag-min-top");
        const minTop = 0; // 离top最小距离，可做边界判断
        oDiv.onmousedown = (e) => {
            const isStop = el.getAttribute("data-isStop");
            console.log(isStop, "isStop");
            // 禁止拖动 如全屏状态
            if (isStop === "true") {
                return;
            }
            oDiv.style.cursor = "move";
            let target = oDiv;
            while (
                window.getComputedStyle(target).position !== "absolute" &&
                target !== document.body
            ) {
                target = target.parentElement as HTMLElement;
            }
            document.onselectstart = () => {
                return false;
            };
            // 鼠标按下，计算当前元素距离可视区的距离
            const disX = e.clientX - target.offsetLeft;
            const disY = e.clientY - target.offsetTop;
            document.onmousemove = (e) => {
                // 通过事件委托，计算移动的距离
                // 因为浏览器里并不能直接取到并且使用clientX、clientY,所以使用事件委托在内部做完赋值
                const l = e.clientX - disX;
                const t = e.clientY - disY;
                const { marginTop: mt, marginLeft: ml } =
                    window.getComputedStyle(target);
                // 计算移动当前元素的位置，并且给该元素样式中的left和top值赋值
                target.style.left = l - parseInt(ml) + "px";
                target.style.top =
                    (t < minTop ? minTop : t) - parseInt(mt) + "px";
            };
            document.onmouseup = (e) => {
                document.onmousemove = null;
                document.onmouseup = null;
                document.onselectstart = null;
            };
            // return false不加的话可能导致黏连，拖到一个地方时div粘在鼠标上不下来，相当于onmouseup失效
            return false;
        };
        oDiv.onmouseup = (e) => {
            oDiv.style.cursor = "default";
        };
    },
    beforeUnmount() {},
    unmounted() {},
};
</script>

<style lang="scss" scoped>
.header {
    width: 100%;
    height: 50px;
    background-color: aquamarine;
}
.content {
    /* height: 150px; */
    height: 100%;
    background-color: bisque;
}
</style>
